using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace DungeonOfDespair
{
    public enum ClipPosition
    {
        Middle,
        TopLeft,
        Top,
        TopRight,
        Right,
        BottomRight,
        Bottom,
        BottomLeft,
        Left
    }

    public class Sprite
    {
        private Image m_image;
        private PointF m_pointPosition;
        private PointF m_pointHotspot;
        private PointF[] m_pointsTransform;
        private PointF[] m_pointsTransformAbsolute;
        private RectangleF m_rectClipBounds;
        private ColorMatrix m_colorMatrix;
        ImageAttributes m_imageAttributes;

        private void UpdateAbsoluteTransform()
        {
            for (int iIndex = 0; iIndex < 3; iIndex++)
            {
                m_pointsTransformAbsolute[iIndex].X
                    = m_pointsTransform[iIndex].X + m_pointPosition.X - m_pointHotspot.X;
                m_pointsTransformAbsolute[iIndex].Y
                    = m_pointsTransform[iIndex].Y + m_pointPosition.Y - m_pointHotspot.Y;
            }
        }

        public Sprite(Image image)
        {
            m_image = image;

            m_pointPosition = new PointF();
            m_pointHotspot = new PointF();
            m_pointsTransform = new PointF[3];
            m_pointsTransformAbsolute = new PointF[3];
            for (int iIndex = 0; iIndex < 3; iIndex++)
            {
                m_pointsTransform[iIndex] = new PointF();
                m_pointsTransformAbsolute[iIndex] = new PointF();
            }
       
            m_rectClipBounds = new RectangleF();

            float[][] fColorMatrix = { 
                new float[5]{1.0f, 0.0f, 0.0f, 0.0f, 0.0f},
                new float[5]{0.0f, 1.0f, 0.0f, 0.0f, 0.0f},
                new float[5]{0.0f, 0.0f, 1.0f, 0.0f, 0.0f},
                new float[5]{0.0f, 0.0f, 0.0f, 1.0f, 0.0f},
                new float[5]{0.0f, 0.0f, 0.0f, 0.0f, 1.0f}};
            m_colorMatrix = new ColorMatrix(fColorMatrix);

            m_imageAttributes = new ImageAttributes();
            m_imageAttributes.SetColorMatrix(m_colorMatrix,
                ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

            ResetClipBounds();
            ResetShape();
        }

        public void ResetClipBounds()
        {
            m_rectClipBounds.X = 0.0f;
            m_rectClipBounds.Y = 0.0f;
            m_rectClipBounds.Width = m_image.Width;
            m_rectClipBounds.Height = m_image.Height;
        }

        public void CentreHotspot(ClipPosition clipPosition)
        {
            switch (clipPosition)
            {
                case ClipPosition.TopLeft:
                case ClipPosition.Left:
                case ClipPosition.BottomLeft:
                    m_pointHotspot.X = 0.0f;
                    break;
                case ClipPosition.Top:
                case ClipPosition.Middle:
                case ClipPosition.Bottom:
                    m_pointHotspot.X = m_rectClipBounds.Width * 0.5f;
                    break;
                case ClipPosition.TopRight:
                case ClipPosition.Right:
                case ClipPosition.BottomRight:
                    m_pointHotspot.X = m_rectClipBounds.Width;
                    break;
            }

            switch (clipPosition)
            {
                case ClipPosition.TopLeft:
                case ClipPosition.Top:
                case ClipPosition.TopRight:
                    m_pointHotspot.Y = 0.0f;
                    break;
                case ClipPosition.Left:
                case ClipPosition.Middle:
                case ClipPosition.Right:
                    m_pointHotspot.Y = m_rectClipBounds.Height * 0.5f;
                    break;
                case ClipPosition.BottomLeft:
                case ClipPosition.Bottom:
                case ClipPosition.BottomRight:
                    m_pointHotspot.Y = m_rectClipBounds.Height;
                    break;
            }

            ResetShape();
        }

        public void ResetShape()
        {
            m_pointsTransform[0].X = 0.0f;
            m_pointsTransform[0].Y = 0.0f;
            m_pointsTransform[1].X = m_rectClipBounds.Width;
            m_pointsTransform[1].Y = 0.0f;
            m_pointsTransform[2].X = 0.0f;
            m_pointsTransform[2].Y = m_rectClipBounds.Height;
        }

        public void Scale(float fScaleX, float fScaleY)
        {
            for (int iIndex = 0; iIndex < 3; iIndex++)
            {
                // centre around hotspot
                m_pointsTransform[iIndex].X -= m_pointHotspot.X;
                m_pointsTransform[iIndex].Y -= m_pointHotspot.Y;

                m_pointsTransform[iIndex].X *= fScaleX;
                m_pointsTransform[iIndex].Y *= fScaleY;

                // reset origin
                m_pointsTransform[iIndex].X += m_pointHotspot.X;
                m_pointsTransform[iIndex].Y += m_pointHotspot.Y;
            }
        }

        public void Rotate(float fAngle)
        {
            float fCosX = (float) Math.Cos(fAngle);
            float fSinX = (float) Math.Sin(fAngle);

            for (int iIndex = 0; iIndex < 3; iIndex++)
            {
                // centre around hotspot
                m_pointsTransform[iIndex].X -= m_pointHotspot.X;
                m_pointsTransform[iIndex].Y -= m_pointHotspot.Y;

                float fX = m_pointsTransform[iIndex].X * fCosX
                    - m_pointsTransform[iIndex].Y * fSinX;
                float fY = m_pointsTransform[iIndex].X * fSinX
                    + m_pointsTransform[iIndex].Y * fCosX;
                m_pointsTransform[iIndex].X = fX;
                m_pointsTransform[iIndex].Y = fY;

                // reset origin
                m_pointsTransform[iIndex].X += m_pointHotspot.X;
                m_pointsTransform[iIndex].Y += m_pointHotspot.Y;
            }
        }

        public void Draw(Graphics graphics)
        {
            UpdateAbsoluteTransform();
            graphics.DrawImage(m_image, m_pointsTransformAbsolute, m_rectClipBounds,
                GraphicsUnit.Pixel, m_imageAttributes);
        }

        public Image Image
        {
            get { return m_image; }
            set
            {
                m_image = value;
                ResetClipBounds();
                ResetShape();
            }
        }

        public float Opacity
        {
            get { return m_colorMatrix.Matrix33; }
            set
            {
                m_colorMatrix.Matrix33 = value;
                m_imageAttributes = new ImageAttributes(); // needed!
                m_imageAttributes.SetColorMatrix(m_colorMatrix);
            }
        }

        public float HotspotX
        {
            get { return m_pointHotspot.X; }
            set
            {
                m_pointHotspot.X = value;
                ResetShape();
            }
        }

        public float HotspotY
        {
            get { return m_pointHotspot.Y; }
            set
            {
                m_pointHotspot.Y = value;
                ResetShape();
            }
        }

        public RectangleF ClipBounds
        {
            get { return m_rectClipBounds; }
            set
            {
                m_rectClipBounds = value;
                ResetShape();
            }
        }

        public float X
        {
            get { return m_pointPosition.X; }
            set { m_pointPosition.X = value; }
        }

        public float Y
        {
            get { return m_pointPosition.Y; }
            set { m_pointPosition.Y = value; }
        }
    }
}
